


#include "qe_def.h"
#include "qe_service.h"
#include "qe_list.h"
#include "qe_platform.h"



struct qe_gbuf *qe_gbuf_create(qe_size_t size)
{
	int allocsize;
	struct qe_gbuf *buf;

	allocsize = sizeof(struct qe_gbuf) + size;
	buf = qe_malloc(allocsize);
	if (!buf) {return QE_NULL;}

	buf->p       = (char *)buf + sizeof(struct qe_gbuf);
	buf->nbytes  = size;
	buf->dsize   = 0;
	buf->dynamic = 1;

	return buf;
}

void qe_gbuf_init(struct qe_gbuf *buf, void *buffer, qe_size_t size)
{
	buf->p      = buffer;
	buf->nbytes = size;
	buf->dsize  = 0;
}

void qe_gbuf_clear(struct qe_gbuf *buf)
{
	qe_memset(buf->p, 0x0, buf->nbytes);
	buf->dsize = 0;
}

void qe_gbuf_backoff(struct qe_gbuf *buf, int back)
{
	qe_memmove(buf->p, buf->p+back, buf->nbytes-back);
	buf->dsize -= back;
}

qe_err_t qe_gbuf_append(struct qe_gbuf *buf, void *data, qe_size_t length)
{
	unsigned int free = buf->nbytes - buf->dsize;

	if (length > free)
		return qe_err_notenough;

	qe_memcpy(buf->p + buf->dsize, data, length);
	buf->dsize += length;
	return qe_ok;
}

void qe_gbuf_pool_init(struct qe_gbuf_pool *pool)
{
	pool->dsize    = 0;
	pool->nbytes   = 0;
	pool->num_bufs = 0;
	qe_list_init(&pool->bufs);
}

void qe_gbuf_pool_clear(struct qe_gbuf_pool *pool)
{
	struct qe_gbuf *p, *t;

	qe_list_foreach_entry_safe(p, t, &pool->bufs, list) {
		qe_list_remove(&p->list);
	}

	pool->dsize    = 0;
	pool->nbytes   = 0;
	pool->num_bufs = 0;
}

qe_err_t qe_gbuf_pool_append(struct qe_gbuf_pool *pool, struct qe_gbuf *buf)
{
	struct qe_gbuf *p;

	if (!pool || !buf)
		return qe_err_param;
	
	qe_list_foreach_entry(p, &pool->bufs, list) {
		if (p->p == buf->p) {
			return qe_err_exist;
		}
	}

	qe_list_append(&p->list, &pool->bufs);
	pool->num_bufs++;
	pool->nbytes += buf->nbytes;
	pool->dsize  += buf->dsize;

	return qe_ok;
}

struct qe_gbuf *qe_gbuf_pool_merge(struct qe_gbuf_pool *pool)
{
	unsigned int free;
	struct qe_gbuf *p, *n;
	struct qe_list_node *node = QE_NULL;

	if (!pool || (!pool->num_bufs) || (!pool->nbytes)) {
		return QE_NULL;
	}

	n = qe_gbuf_create(pool->nbytes);
	if (!n) {
		return QE_NULL;
	}

	qe_list_foreach(node, &(pool->bufs)) {
		p = qe_list_entry(node, struct qe_gbuf, list);
		free = n->nbytes - n->dsize;
		if ((p->dsize > 0) && (p->dsize <= free)) {
			qe_memcpy(n->p + n->dsize, p->p, p->dsize);
			n->dsize += p->dsize;
		}
	}

	return n;
}

/**
 * @brief Initialize a RingBuffer struct through the buffer
 * 
 * @param rb     : RingBuffer struct
 * @param buf    : data buffer
 * @param length : buffer length
 */
void qe_ringbuffer_init(struct qe_ringbuffer *rb, char *buf, unsigned int length)
{
	rb->head = 0;
	rb->tail = 0;
	rb->count = 0;
	rb->buf = buf;
	rb->length = length;
}

/**
 * @brief Create a RingBuffer with size
 * 
 * @param size : the memsize to create
 * @return struct qe_ringbuffer* 
 * @note use free to release RingBuffer's memory
 */
struct qe_ringbuffer *qe_ringbuffer_create(qe_size_t size)
{
    char *buf;
    struct qe_ringbuffer *ring = qe_malloc(sizeof(struct qe_ringbuffer)+size);
    if (!ring)
        return QE_NULL;

    buf = (char *)ring + sizeof(struct qe_ringbuffer);
    qe_ringbuffer_init(ring, buf, size);
    return ring;
}

/**
 * @brief Clear a RingBuffer, this function will not modify the data
 * 
 * @param rb : RingBuffer pointer
 */
void qe_ringbuffer_clear(struct qe_ringbuffer *rb)
{
	rb->head = 0;
	rb->tail = 0;
	rb->count = 0;
}

/**
 * @brief Write data to RingBuffer
 * 
 * @param rb  : RingBuffer pointer
 * @param buf : write buffer data
 * @param len : write buffer length
 */
void qe_ringbuffer_write(struct qe_ringbuffer *rb, char *buf, unsigned int len)
{
	unsigned int size = 0;
	
	if ((rb->tail + len) <= rb->length) {
		qe_memcpy(rb->buf+rb->tail, buf, len);
	} else {
		size = rb->length-rb->tail;
		qe_memcpy(rb->buf+rb->tail, buf, size);
		qe_memcpy(rb->buf, buf+size, len-size);
	}

	rb->tail = (rb->tail + len) % rb->length;
	rb->count += len;
}

/**
 * @brief Read data from RingBuffer
 * 
 * @param rb  : RingBuffer pointer
 * @param buf : read buffer pointer
 * @param len : read buffer length
 */
void qe_ringbuffer_read(struct qe_ringbuffer *rb, char *buf, unsigned int len)
{
	unsigned int size;
	
	if ((rb->head + len) <= rb->length) {
		qe_memcpy(buf, rb->buf+rb->head, len);
	} else {
		size = rb->length - rb->head;
		qe_memcpy(buf, rb->buf+rb->head, size);
		qe_memcpy(buf+size, rb->buf, len-size);
	}

	rb->head = (rb->head + len) % rb->length;
	rb->count -= len;
}

/**
 * @brief Get the valid data size in RingBuffer
 * 
 * @param rb : RingBuffer pointer
 * @return unsigned int 
 */
unsigned int qe_ringbuffer_wait(struct qe_ringbuffer *rb)
{
	return rb->count;
}

/**
 * @brief Get the data memory size in RingBuffer
 * 
 * @param rb : RingBuffer pointer
 * @return unsigned int 
 */
unsigned int qe_ringbuffer_size(struct qe_ringbuffer *rb)
{
	return rb->length;
}